<template>
  <div :class="prefix" ref="virtualListCom" @wheel.prevent="initDisplay">
    <!-- 虚拟滚动条 -->
    <div :class="`${prefix}-scrollbar`">
      <div :class="`${prefix}-scrollbar-item`"></div>
    </div>
    <!-- 虚拟列表 -->
    <div :class="`${prefix}-box`" ref="itemBox">
      <div :class="`${prefix}-box-item`" v-for="item in list" :key="item" :style="{ height: virtualListConfig.itemHeight + 'px' }">
        {{ item }}
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, reactive, computed, nextTick } from 'vue';
const prefix = 'virtualListCom';

// 总数据
const totalList = ref([]);

// 关于虚拟列表的控制
const virtualListConfig = reactive({
  totalScrollDistance: 0, // 增量是多少
  itemHeight: 80, // 每条高度
  startIndex: 0, // 开始截取的索引
  endIndex: 0, // 结束截取的索引
  translate: 0, // 移动了多少
});

// 关于虚拟滚动条的控制
const scrollbarConfig = reactive({
  height: 0,
  top: 0,
});

// 创建总数据
const initList = () => {
  for (let i = 0; i < 20; i++) {
    totalList.value.push(i + 1);
  }
};

// 截取的长度
const list = computed(() => {
  return totalList.value.slice(virtualListConfig.startIndex, virtualListConfig.endIndex);
});

// 初始化展示多少条?
const virtualListCom = ref<any>();
const itemBox = ref();

/*
 *  这是已知子元素高度的做法
 *  子元素未知高度:
 *  1. 设定预渲染值, 一屏渲染6个 , 可以是用户选择, 也可以根据逻辑判断
 *  1.1 用户渲染 , 需要用户判断必须渲染超出父元素的高度的子元素个数(预估) , 避免数据少 , 无法进行初始化画布补全
 *  1.2 逻辑渲染 , 逻辑渲染需要根据itemBox的渲染高度判断,动态选择截取个数(一屏幕可能是2个 , 也可能是10个)
 *  但是itemBox高度必须比virtualListCom可视窗口高, 避免数据高度小 , 无法进行初始化画布补全
 */

const initDisplay = (e) => {
  const { clientHeight } = virtualListCom.value;
  const { deltaY } = e;
  // 向上滑动的执行截停时机:滑动到了顶部
  const ceaseUpwards = deltaY < 0 && virtualListConfig.startIndex == 0;
  // 向下滑动的执行截停时机:滑动到了底部
  const ceaseDownwards = deltaY > 0 && virtualListConfig.endIndex > totalList.value.length - 1;
  // 向上动作截停
  if (ceaseUpwards) {
    if (virtualListConfig.translate !== 0) {
      console.log(virtualListConfig.translate);
      virtualListConfig.translate = 0;
      itemBox.value.style.transform = `translateY(${0}px)`;
    }
    return;
  }
  // 向下动作截停
  if (ceaseDownwards) {
    console.log(virtualListConfig.translate);
    if (virtualListConfig.translate == 0) {
      virtualListConfig.translate = clientHeight - itemBox.value.offsetHeight;
      itemBox.value.style.transform = `translateY(${virtualListConfig.translate}px)`;
    }
    return;
  }

  // 初始化截取数据
  if (deltaY == undefined) {
    // 初始化截取索引为0的
    virtualListConfig.startIndex = 0;
  } else {
    // 滚动的增量
    virtualListConfig.totalScrollDistance += deltaY > 0 ? 25 : -25;
  }

  console.log(virtualListConfig.totalScrollDistance, '滚动的增量');
  // 开始截取的索引:向下取整
  virtualListConfig.startIndex = Math.floor(virtualListConfig.totalScrollDistance / virtualListConfig.itemHeight);
  console.log(virtualListConfig.startIndex, '开始截取');
  // 结束截取的索引:向上取整
  virtualListConfig.endIndex = Math.ceil(virtualListConfig.startIndex + clientHeight / virtualListConfig.itemHeight);
  console.log(virtualListConfig.endIndex, '结束截取');

  console.log(list.value, '截取的数组');
};

// 初始化的虚拟滚动条

/*
 * 根据子元素高度 * 每个子元素高度 算出数据的总高度;
 */

onMounted(() => {
  initList();
  initDisplay(virtualListCom.value);
});
</script>

<style lang="scss" scoped>
.virtualListCom {
  width: 100%;
  height: calc($height - $padding * 2);
  border: 1px solid #000;
  overflow-y: hidden;
  &-box {
    &-item {
      width: 100%;
      border: 1px solid #000;
      border-top: 0;
    }
  }
}
</style>
